package com.example.project.controller.project;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.compress.utils.Lists;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.example.message.service.MessageService;
import com.example.project.annotation.IssueOperation;
import com.example.project.annotation.Log;
import com.example.project.core.controller.BaseController;
import com.example.project.core.domain.AjaxResult;
import com.example.project.core.page.TableDataInfo;
import com.example.project.entity.Attachment;
import com.example.project.entity.Issue;
import com.example.project.entity.IssueCategorie;
import com.example.project.entity.IssuePrioritie;
import com.example.project.entity.IssueRelation;
import com.example.project.entity.IssueStatus;
import com.example.project.entity.Journal;
import com.example.project.entity.JournalDetail;
import com.example.project.entity.Project;
import com.example.project.entity.TimeActivitie;
import com.example.project.entity.TimeEntrie;
import com.example.project.entity.Tracker;
import com.example.project.entity.User;
import com.example.project.entity.Watcher;
import com.example.project.enums.BusinessType;
import com.example.project.service.AttachmentService;
import com.example.project.service.CommonService;
import com.example.project.service.IssueCategorieService;
import com.example.project.service.IssueOperationRecordService;
import com.example.project.service.IssuePrioritieService;
import com.example.project.service.IssueService;
import com.example.project.service.IssueStatusService;
import com.example.project.service.JournalDetailService;
import com.example.project.service.JournalService;
import com.example.project.service.ProjectService;
import com.example.project.service.TimeActivitieService;
import com.example.project.service.IssueRelationService;
import com.example.project.service.TimeEntrieService;
import com.example.project.service.TrackerService;
import com.example.project.service.UserService;
import com.example.project.service.WatcherService;
import com.example.project.utils.DateUtils;
import com.example.project.utils.NumberConvertUtil;
import com.example.project.utils.StringUtils;
import com.example.project.utils.TimeFormatter;
import com.example.project.utils.file.FileUtils;
import com.example.project.utils.poi.ExcelUtil;

/**
 * 问题，存储项目中的任务、缺陷等问题Controller
 * 
 * @author ruoyi
 * @date 2025-09-19
 */
@Controller
@RequestMapping("/project/issue")
public class IssueController extends BaseController {

	private String prefix = "pm/issue";

	@Autowired
	private CommonService commonService;

	@Autowired
	private UserService userService;

	@Autowired
	private ProjectService projectsService;

	@Autowired
	private IssueService issueService;

	@Autowired
	private IssueStatusService issueStatusService;

	@Autowired
	private IssueCategorieService issueCategorieService;

	@Autowired
	private IssuePrioritieService issuePrioritieService;

	@Autowired
	private JournalService journalService;

	@Autowired
	private JournalDetailService journalDetailService;

	@Autowired
	private TrackerService trackersService;

	@Autowired
	private AttachmentService attachmentService;

	@Autowired
	private WatcherService watcherService;

	@Autowired
	private TimeActivitieService timeActivitieService;

	@Autowired
	private TimeEntrieService timeEntrieService;

	@Autowired
	private IssueOperationRecordService issueOperationRecordService;

	@Autowired
	private IssueRelationService issueRelationService;

	@Autowired
	private MessageService messageService;

	/**
	 * 新建问题
	 */
	@Log(title = "发布需求", businessType = BusinessType.EXPORT)
	@RequiresPermissions("project:issue:add")
	@GetMapping("/new")
	public String newIssues(ModelMap mmap) {
		// 项目列表
		List<Project> projectList = projectsService.findAllList(1);
		mmap.put("projectList", projectList);

		// 跟踪列表
		List<Tracker> trackerList = trackersService.findAllList();
		mmap.put("trackerList", trackerList);
		// 状态列表
		List<IssueStatus> issueStatuseList = issueStatusService.findAllList();
		mmap.put("issueStatuseList", issueStatuseList);
		// 用户
		List<User> userList = userService.findAllList();
		mmap.put("userList", userList);
		// 优先级
		List<IssuePrioritie> issuePrioritieList = issuePrioritieService.findAllList();
		mmap.put("issuePrioritieList", issuePrioritieList);

		// 问题类别
		List<IssueCategorie> issueCategorieList = commonService.getIssueCategorieList();
		mmap.put("issueCategorieList", issueCategorieList);
		String curDate = DateUtils.getDate();
		mmap.put("curDate", curDate);
		return prefix + "/issue_new";
	}

	@RequiresPermissions("project:issue:view")
	@GetMapping("index")
	public String issueIndex(ModelMap mmap, Long projectId, @DefaultValue("false") boolean goBack) {
		mmap.put("projectId", projectId);
		mmap.put("goBack", goBack);
		// 项目列表
		List<Project> projectList = projectsService.findAllList(1);
		mmap.put("projectList", projectList);
		// 跟踪列表
		List<Tracker> trackerList = trackersService.findAllList();
		mmap.put("trackerList", trackerList);
		// 优先级
		List<IssuePrioritie> issuePrioritieList = issuePrioritieService.findAllList();
		mmap.put("issuePrioritieList", issuePrioritieList);
		// 状态列表
		List<IssueStatus> issueStatuseList = issueStatusService.findAllList();
		mmap.put("issueStatuseList", issueStatuseList);
		// 用户
		List<User> userList = userService.findAllList();
		mmap.put("userList", userList);

		// 问题类别
		List<IssueCategorie> issueCategorieList = issueCategorieService.findAllList();
		mmap.put("issueCategorieList", issueCategorieList);
		if (!goBack) {
			mmap.put("curUserId", getUserId());
		}
		mmap.put("curUser", getUser());
		return prefix + "/issue_index";
	}

	@RequiresPermissions("project:issue:view")
	@GetMapping()
	public String issue(ModelMap mmap) {
		// 项目列表
		List<Project> projectList = projectsService.findAllList(1);
		mmap.put("projectList", projectList);
		// 优先级
		List<IssuePrioritie> issuePrioritieList = issuePrioritieService.findAllList();
		mmap.put("issuePrioritieList", issuePrioritieList);
		// 跟踪列表
		List<Tracker> trackerList = trackersService.findAllList();
		mmap.put("trackerList", trackerList);
		// 状态列表
		List<IssueStatus> issueStatuseList = issueStatusService.findAllList();
		mmap.put("issueStatuseList", issueStatuseList);
		// 用户
		List<User> userList = userService.findAllList();
		mmap.put("userList", userList);

		// 问题类别
		List<IssueCategorie> issueCategorieList = issueCategorieService.findAllList();
		mmap.put("issueCategorieList", issueCategorieList);
		mmap.put("curUserId", getUserId());
		return prefix + "/issue";
	}

	/**
	 * 查询问题，存储项目中的任务、缺陷等问题列表
	 */
	@RequiresPermissions("project:issue:list")
	@PostMapping("/list")
	@ResponseBody
	public TableDataInfo list(Issue issues) {
		startPage();
		List<Issue> list = issueService.selectIssuesList(issues);
		list = issueService.convertToIssuesList(list);
		return getDataTable(list);
	}

	/**
	 * 导出问题，存储项目中的任务、缺陷等问题列表
	 */
	@RequiresPermissions("project:issue:export")
	@Log(title = "需求导出", businessType = BusinessType.EXPORT)
	@PostMapping("/export")
	@ResponseBody
	public AjaxResult export(Issue issues) {
		List<Issue> list = issueService.selectIssuesList(issues);
		ExcelUtil<Issue> util = new ExcelUtil<Issue>(Issue.class);
		return util.exportExcel(list, "需求数据");
	}

	/**
	 * 新增问题，存储项目中的任务、缺陷等问题
	 */
	@RequiresPermissions("project:issue:add")
	@GetMapping("/add")
	public String add() {
		return prefix + "/add";
	}

	/**
	 * 新增保存问题，存储项目中的任务、缺陷等问题
	 */
	@RequiresPermissions("project:issue:add")
	@Log(title = "需求新增", businessType = BusinessType.INSERT)
	@IssueOperation(type = 0, value = "发布需求")
	@PostMapping("/add")
	@ResponseBody
	public AjaxResult addSave(Issue issue,
			@RequestParam(value = "uploadedFiles", required = false) String uploadedFilesJson) {
		issue.setCreateBy(getLoginName());
		issue.setAuthorId(getUserId());
		long result = issueService.insertIssues(issue);
		if (result > 0) {
			// 保存附件
			if (uploadedFilesJson != null && !uploadedFilesJson.isEmpty()) {
				attachmentService.saveAttachments(issue.getId(), uploadedFilesJson);
			}
			// 发送消息
			messageService.sendIssueMessage(issue);
		}
		issueOperationRecordService.publicRequirement(issue.getId());
		return result > 0 ? success(issue) : error();
	}

	@GetMapping("/detail/{id}")
	@ResponseBody
	public AjaxResult issueDetail(@PathVariable("id") Long issueId) {
		Issue issueInfo = issueService.selectIssuesById(issueId);
		return success(issueInfo);
	}

	/**
	 * 问题详情
	 */
	@RequiresPermissions("project:issue:view")
	@GetMapping("/{id}")
	public String detail(@PathVariable("id") Long issueId, ModelMap mmap) {
		Issue issueInfo = issueService.selectIssuesById(issueId);
		if (issueInfo == null) {
			return prefix + "/issue_not_found";
		}
		mmap.put("issueInfo", issueInfo);
		if (issueInfo != null) {
			LocalDateTime createTime = issueInfo.getCreateTime();
			if (createTime != null) {
				String timeSinceCreation = DateUtils.calculateTimeSince(createTime);
				mmap.put("timeSinceCreation", timeSinceCreation);
			}
			LocalDateTime updateTime = issueInfo.getUpdateTime();
			if (updateTime != null) {
				String timeSinceUpdate = DateUtils.calculateTimeSince(updateTime);
				mmap.put("timeSinceUpdate", timeSinceUpdate);
			}
			List<Attachment> attachmentList = attachmentService.queryAttachmentsListByIdAndType(issueInfo.getId(),
					Issue.class.getSimpleName());
			attachmentList.forEach(info -> {
				info.setFileSizeValue(FileUtils.formatFileSize(info.getFilesize()));
			});
			mmap.put("attachmentList", attachmentList);

			LocalDateTime collectionTime = issueInfo.getCollectionTime();
			LocalDateTime completionTime = issueInfo.getCompletionTime();
			if (collectionTime != null && completionTime != null) {
				String timeDifference = DateUtils.calculateTimeDifference(collectionTime, completionTime);
				mmap.put("timeDifference", timeDifference);
			}
		}

		mmap.put("curUserId", getUserId());
		User user = getUser();
		mmap.put("curUser", user);

		// 相关需求
		List<IssueRelation> relationList = issueRelationService.queryIssueRelationListByIssueId(issueId);
		mmap.put("relationList", relationList);

		// 查询最近更新人
		JournalDetail lastUpdatedJournalDetail = journalDetailService.queryByIssueIdAndPropKey(issueId, "assignedToId",
				issueInfo.getAuthorId());
		if (lastUpdatedJournalDetail != null) {
			String value = lastUpdatedJournalDetail.getValue();
			Long userId = NumberConvertUtil.safeParseLong(value, 0L);
			if (userId != 0) {
				User userInfo = commonService.getUserInfo(userId);
				mmap.put("lastUpdatedByNonAuthor",
						userInfo != null ? userInfo.getUserName() : userId == 1 ? "管理员" : "无");
				mmap.put("lastUpdatedJournalDetail", lastUpdatedJournalDetail);
			}
		}

		// 历史记录
		List<Journal> journalList = journalService.findByJournalizedId(issueId);
		if (!journalList.isEmpty()) {
			journalList.forEach(info -> {
				long journalId = info.getId();
				List<JournalDetail> detailList = journalDetailService.findListByJournalId(journalId);
				detailList.forEach(detail -> {
					String showDetail = journalDetailService.showDetail(detail);
					detail.setShowDetail(showDetail);
				});
				info.setDetailList(detailList);
				List<Long> attachmentids = detailList.stream()
						.filter(detail -> "attachment".equals(detail.getProperty())).map(JournalDetail::getValue)
						.map(Long::parseLong).toList();
				if (!attachmentids.isEmpty()) {
					// 设置attachmentList
					List<Attachment> attachmentList = attachmentService.selectAttachmentListByIds(attachmentids);
					info.setAttachmentList(attachmentList);
				}

				LocalDateTime createTime = info.getCreatedOn();
				if (createTime != null) {
					String timeSinceCreation = DateUtils.calculateTimeSince(createTime);
					info.setTimeSinceCreation(timeSinceCreation);
				}
			});
		}
		mmap.put("journalList", journalList);
		List<Journal> journalNoteList = journalList.stream().filter(info -> StringUtils.isNotBlank(info.getNotes()))
				.toList();
		mmap.put("journalNoteList", journalNoteList);

		List<Journal> journalPropertielist = journalList.stream().filter(info -> !info.getDetailList().isEmpty())
				.toList();
		mmap.put("journalPropertielist", journalPropertielist);

		// 耗时查询
		TimeEntrie timeEntries = new TimeEntrie();
		timeEntries.setIssueId(issueId);
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("dataScope", "order by create_time asc");
		timeEntries.setParams(params);
		List<TimeEntrie> entrieList = timeEntrieService.selectTimeEntriesList(timeEntries);
		if (!entrieList.isEmpty()) {
			Map<Long, TimeActivitie> timeActivitieMap = commonService.getTimeActivitieMap();
			entrieList.forEach(info -> {
				LocalDateTime createTime = info.getCreateTime();
				if (createTime != null) {
					String timeSinceCreation = DateUtils.formatUpdatedTimeOnly(createTime);
					info.setTimeSinceCreation(timeSinceCreation);
				}

				Long authorId = info.getAuthorId();
				User userInfo = commonService.getUserInfo(authorId);
				info.setAuthorName(userInfo != null ? userInfo.getUserName() : "");

				Long activityId = info.getActivityId();
				TimeActivitie timeActivitie = timeActivitieMap.get(activityId);
				info.setActivityName(timeActivitie != null ? timeActivitie.getName() : "");

				String hours = info.getHours();
				if (StringUtils.isNotEmpty(hours)) {
					String formatHours = TimeFormatter.formatHoursToTime(Double.parseDouble(hours));
					info.setFormatHours(formatHours);
				}
			});

			// 计算hours字段的总和
			double totalHours = entrieList.stream()
					.filter(info -> info != null && StringUtils.isNotEmpty(info.getHours()))
					.mapToDouble(info -> NumberConvertUtil.safeParseDouble(info.getHours(), 0.0)).sum();
			String entrieHours = TimeFormatter.formatHoursToTime(totalHours);
			mmap.put("entrieHours", entrieHours);
		}
		mmap.put("entrieList", entrieList);

		return prefix + "/issue_detail";
	}

	/**
	 * 修改问题，存储项目中的任务、缺陷等问题
	 */
	@RequiresPermissions("project:issue:edit")
	@GetMapping("/edit/{id}")
	public String edit(@PathVariable("id") Long id, @DefaultValue("0") Integer buttonShow, ModelMap mmap) {
		mmap.put("buttonShow", buttonShow);
		Issue issueInfo = issueService.selectIssuesById(id);
		if (issueInfo == null) {
			return prefix + "/issue_not_found";
		}
		if (issueInfo.getStartDate() == null) {
			LocalDateTime createTime = issueInfo.getCreateTime();
			if (createTime != null) {
				issueInfo.setStartDate(createTime.toLocalDate());
			}
		}
		mmap.put("issueInfo", issueInfo);
		// 项目列表
		List<Project> projectList = projectsService.findAllList(1);
		mmap.put("projectList", projectList);
		// 优先级
		List<IssuePrioritie> issuePrioritieList = issuePrioritieService.findAllList();
		mmap.put("issuePrioritieList", issuePrioritieList);
		// 跟踪列表
		List<Tracker> trackerList = trackersService.findAllList();
		mmap.put("trackerList", trackerList);
		// 状态列表
		List<IssueStatus> issueStatuseList = issueStatusService.findAllList();
		mmap.put("issueStatuseList", issueStatuseList);
		// 用户
		List<User> userList = userService.findAllList();
		mmap.put("userList", userList);

		// 问题类别
		List<IssueCategorie> issueCategorieList = issueCategorieService.findAllList();
		mmap.put("issueCategorieList", issueCategorieList);
		mmap.put("curUserId", getUserId());

		return prefix + "/edit";
	}

	/**
	 * 修改保存问题，存储项目中的任务、缺陷等问题
	 */
	@RequiresPermissions("project:issue:edit")
	@Log(title = "需求修改", businessType = BusinessType.UPDATE)
	@PostMapping("/edit")
	@ResponseBody
	public AjaxResult editSave(Issue issue,
			@RequestParam(value = "uploadedFiles", required = false) String uploadedFilesJson) {
		int result = issueService.updateIssues(issue, uploadedFilesJson);
		return toAjax(result);
	}

	/**
	 * 删除问题，存储项目中的任务、缺陷等问题
	 */
	@RequiresPermissions("project:issue:remove")
	@Log(title = "需求删除", businessType = BusinessType.DELETE)
	@PostMapping("/remove")
	@ResponseBody
	public AjaxResult remove(String ids) {
		return toAjax(issueService.deleteIssuesByIds(ids));
	}

	/**
	 * 关注问题
	 */
	@Log(title = "关注需求", businessType = BusinessType.UPDATE)
	@PostMapping("/watch/{id}")
	@ResponseBody
	public AjaxResult watch(@PathVariable("id") Long issueId) {
		Long userId = getUserId();
		boolean result = watcherService.watch("Issue", issueId, userId);
		if (result) {
			return AjaxResult.success("关注成功");
		} else {
			return AjaxResult.error("关注失败");
		}
	}

	/**
	 * 获取项目类别列表
	 */
	@GetMapping("/categories/{projectId}")
	@ResponseBody
	public AjaxResult getCategoriesByProjectId(@PathVariable("projectId") Long projectId) {
		IssueCategorie categorie = new IssueCategorie();
		categorie.setProjectId(projectId);
		List<IssueCategorie> categorieList = issueCategorieService.selectIssueCategorieList(categorie);
		return AjaxResult.success(categorieList);
	}

	/**
	 * 取消关注问题
	 */
	@Log(title = "取消关注需求", businessType = BusinessType.UPDATE)
	@PostMapping("/unwatch/{id}")
	@ResponseBody
	public AjaxResult unwatch(@PathVariable("id") Long issueId) {
		Long userId = getUserId();
		boolean result = watcherService.unwatch("Issue", issueId, userId);
		if (result) {
			return AjaxResult.success("取消关注成功");
		} else {
			return AjaxResult.error("取消关注失败");
		}
	}

	/**
	 * 检查是否关注问题
	 */
	@GetMapping("/isWatched/{id}")
	@ResponseBody
	public AjaxResult isWatched(@PathVariable("id") Long issueId) {
		Long userId = getUserId();
		boolean isWatched = watcherService.isWatched("Issue", issueId, userId);
		return AjaxResult.success(isWatched);
	}

	/**
	 * 获取问题的关注者列表
	 */
	@GetMapping("/watchers/{id}")
	@ResponseBody
	public AjaxResult getWatchers(@PathVariable("id") Long issueId) {
		List<Watcher> watchers = watcherService.getWatchers("Issue", issueId);
		if (!watchers.isEmpty()) {
			Map<Long, User> userMap = commonService.getUserMap();
			watchers.forEach(info -> {
				Long userId = info.getUserId();
				User user = userMap.get(userId);
				info.setUserName(user != null ? user.getUserName() : "");
			});
		}
		return AjaxResult.success(watchers);
	}

	/**
	 * 领取
	 * 
	 * @param issueId
	 * @return
	 */
	@Log(title = "领取需求", businessType = BusinessType.UPDATE)
	@GetMapping("/claimIssue/{id}")
	@ResponseBody
	public AjaxResult claimIssue(@PathVariable("id") Long issueId) {
		int result = 0;
		Long userId = getUserId();
		Issue issue = issueService.selectIssuesById(issueId);
		if (issue != null) {
			Long assignedToId = issue.getAssignedToId();
			if (assignedToId == userId) {
				return success(-1);
			}
			// 分配指派人员
			// 修改状态为进行中
			issue.setRecipient(userId);
			issue.setCollectionTime(LocalDateTime.now());
			result = issueService.setupAssignedToId(issue, userId, 2L);
			if (result > 0) {
				issueStatsService.recordIssueProcessingStats(issueId, 1, issue.getStatusId(), 2L);
			}
		}
		return success(result);
	}

	/**
	 * 提交
	 * 
	 * @param issueId
	 * @param comment
	 * @return
	 */
	@Log(title = "完成需求", businessType = BusinessType.UPDATE)
	@PostMapping("/submitIssue/{id}")
	@ResponseBody
	public AjaxResult submitIssue(@PathVariable("id") Long issueId, String comment) {
		int result = 0;
		Issue issue = issueService.selectIssuesById(issueId);
		if (issue != null) {
			Long authorId = issue.getAuthorId();
			// 设置提交说明
			if (comment != null && !comment.trim().isEmpty()) {
				issue.setNotes(comment);
			}
			// 分配指派人员
			// 修改状态为待测试
			issue.setDoneRatio(100);
			issue.setCompletionTime(LocalDateTime.now());
			result = issueService.setupAssignedToId(issue, authorId, 3L);
			if (result > 0) {
				issueStatsService.recordIssueProcessingStats(issueId, 2, issue.getStatusId(), 3L);
			}
		}
		return success(result);
	}

	@Log(title = "审核需求", businessType = BusinessType.UPDATE)
	@PostMapping("/reviewIssue/{id}")
	@ResponseBody
	public AjaxResult reviewIssue(@PathVariable("id") Long issueId, int status, String comment) {
		int result = 0;
		Issue issue = issueService.selectIssuesById(issueId);
		if (issue != null) {
			issue.setNotes(comment);
			if (status == 0) {
				// 不通过
				Long recipient = issue.getRecipient();
				result = issueService.setupAssignedToId(issue, recipient, 5L);
				if (result > 0) {
					issueStatsService.recordIssueProcessingStats(issueId, 3, issue.getStatusId(), 5L);
				}
			} else {
				// 通过 - 保持当前指派给作者，只修改状态
				Long authorId = issue.getAuthorId();
				result = issueService.setupAssignedToId(issue, authorId, 4L);
				if (result > 0) {
					issueStatsService.recordIssueProcessingStats(issueId, 3, issue.getStatusId(), 4L);
				}
			}
		}
		return success(result);
	}

	/**
	 * 登记工时
	 */
	@GetMapping("/logWorkingHours/{id}")
	public String logWorkingHours(@PathVariable("id") Long id, ModelMap mmap) {
		Issue issueInfo = issueService.selectIssuesById(id);
		if (issueInfo == null) {
			return prefix + "/issue_not_found";
		}
		mmap.put("issueInfo", issueInfo);

		mmap.put("curUser", getUser());

		// 时间跟踪
		List<TimeActivitie> activitieList = timeActivitieService.selectTimeActivitieList(null);
		mmap.put("activitieList", activitieList);
		return prefix + "/issue_work";
	}

	@Log(title = "登记工时", businessType = BusinessType.UPDATE)
	@PostMapping("/saveEntrie")
	@ResponseBody
	public AjaxResult saveEntrie(TimeEntrie entrie, int doneRatio, String notes,
			@RequestParam(value = "uploadedFiles", required = false) String uploadedFilesJson) {
		Long userId = getUserId();
		Long issueId = entrie.getIssueId();
		Issue issue = issueService.selectIssuesById(issueId);
		issue.setNotes(notes);
		issue.setDoneRatio(doneRatio);
		issueService.updateIssues(issue, uploadedFilesJson);
		int result = timeEntrieService.save(entrie, issue, userId);
		return success(result);
	}

	@GetMapping("/autoComplete")
	@ResponseBody
	public AjaxResult autoComplete(Long issueId) {
		Issue issue = issueService.selectIssuesById(issueId);
		ArrayList<Issue> lists = Lists.newArrayList();
		lists.add(issue);
		return success(lists);
	}
}
